package Util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;

/**
 * Classe responsável por inicializar as tabelas no inicio do programa
 *
 * @author Danilo
 */
public class Inicializar {

    /**
     * Métedo responsável por carregar os Simbolos
     *
     * @return HashMap
     */
    public static HashMap<Integer, Character> carregaSimbolos() {

        HashMap<Integer, Character> simbolos = new HashMap<>();
        simbolos.put(1, '/');
        simbolos.put(2, '*');
        simbolos.put(4, '<');
        simbolos.put(5, '>');
        simbolos.put(6, '<');
        simbolos.put(7, '=');
        simbolos.put(8, ';');
        simbolos.put(9, '-');
        simbolos.put(10, '+');
        simbolos.put(11, ':');
        simbolos.put(12, ',');
        simbolos.put(13, '(');
        simbolos.put(14, ')');
        simbolos.put(15, '{');
        simbolos.put(16, '}');
        simbolos.put(17, '.');

        return simbolos;
    }

    /**
     * Métedo responsável por carregar as palavra reservada.
     *
     * @return HashMap
     */
    public static HashMap carregaPalavrasReservadas() {
        HashMap<Integer, String> palavrasReservadas = new HashMap<>();
        palavrasReservadas.put(0, "program");
        palavrasReservadas.put(1, "begin");
        palavrasReservadas.put(2, "end");
        palavrasReservadas.put(3, "real");
        palavrasReservadas.put(4, "integer");
        palavrasReservadas.put(5, "write");
        palavrasReservadas.put(6, "while");
        palavrasReservadas.put(7, "if");
        palavrasReservadas.put(8, "var");
        palavrasReservadas.put(9, "then");

        return palavrasReservadas;
    }

    /**
     * Métedo responsável por carregar todos primeiro da lingaguem.
     *
     * @return Hashmap
     */
    public static HashMap carregaPrimeiros() {

        HashMap<String, Collection<String>> listaPrimeiro = new HashMap<>();

        listaPrimeiro.put("pPrograma", pPrograma());
        listaPrimeiro.put("pCorpo", pCorpo());
        listaPrimeiro.put("pDc", pDc());
        listaPrimeiro.put("pDcV", pDcV());
        listaPrimeiro.put("pTipoVar", pTipoVar());
        listaPrimeiro.put("pVariaveis", pVariaveis());
        listaPrimeiro.put("pMaisVar", pMaisVar());
        listaPrimeiro.put("pDcP", pDcP());
        listaPrimeiro.put("pParametros", pParametros());
        listaPrimeiro.put("pListaPar", pListaPar());
        listaPrimeiro.put("pMaisPar", pMaisPar());
        listaPrimeiro.put("pCorpoP", pCorpoP());
        listaPrimeiro.put("pDcLoc", pDcLoc());
        listaPrimeiro.put("pListaArg", pListaArg());
        listaPrimeiro.put("pArgumentos", pArgumentos());
        listaPrimeiro.put("pMaisIdent", pMaisIdent());
        listaPrimeiro.put("pPFalsa", pPFalsa());
        listaPrimeiro.put("pComandos", pComandos());
        listaPrimeiro.put("pCmd", pCmd());
        listaPrimeiro.put("pCondicao", pCondicao());
        listaPrimeiro.put("pRelacao", pRelacao());
        listaPrimeiro.put("pExpressao", pExpressao());
        listaPrimeiro.put("pOpUn", pOpUn());
        listaPrimeiro.put("pOutrosTermos", pOutrosTermos());
        listaPrimeiro.put("pOpAd", pOpAd());
        listaPrimeiro.put("pTermo", pTermo());
        listaPrimeiro.put("pMaisFatores", pMaisFatores());
        listaPrimeiro.put("pOpMul", pOpMul());
        listaPrimeiro.put("pFator", pFator());

        return listaPrimeiro;
    }

    //<editor-fold defaultstate="collapsed" desc=" Metodos para carregar os primeiros"> 
    private static ArrayList<String> pPrograma() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("program");
        return arrayList;
    }

    private static ArrayList<String> pCorpo() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("var");
        arrayList.add("procedure");
        arrayList.add("begin");
        arrayList.add("VAZIO");
        return arrayList;
    }

    private static ArrayList<String> pDc() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("var");
        arrayList.add("procedure");
        arrayList.add("VAZIO");

        return arrayList;
    }

    private static ArrayList<String> pDcV() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("var");
        arrayList.add("VAZIO");

        return arrayList;
    }

    private static ArrayList<String> pTipoVar() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("Real");
        arrayList.add("Inteiro");

        return arrayList;
    }

    private static ArrayList<String> pVariaveis() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("ident");

        return arrayList;
    }

    private static ArrayList<String> pMaisVar() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add(",");
        arrayList.add("VAZIO");

        return arrayList;
    }

    private static ArrayList<String> pDcP() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("procedure");
        arrayList.add("VAZIO");

        return arrayList;
    }

    private static ArrayList<String> pParametros() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("(");
        arrayList.add("VAZIO");

        return arrayList;
    }

    private static ArrayList<String> pListaPar() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("ident");

        return arrayList;
    }

    private static ArrayList<String> pMaisPar() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add(";");
        arrayList.add("VAZIO");

        return arrayList;
    }

    private static ArrayList<String> pCorpoP() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("var");
        arrayList.add("begin");
        arrayList.add("VAZIO");

        return arrayList;
    }

    private static ArrayList<String> pDcLoc() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("var");
        arrayList.add("VAZIO");

        return arrayList;
    }

    public static ArrayList<String> pListaArg() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("(");
        arrayList.add("VAZIO");

        return arrayList;
    }

    private static ArrayList<String> pArgumentos() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("ident");

        return arrayList;
    }

    private static ArrayList<String> pMaisIdent() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add(";");
        arrayList.add("VAZIO");

        return arrayList;
    }

    private static ArrayList<String> pPFalsa() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("else");
        arrayList.add("VAZIO");

        return arrayList;
    }

    private static ArrayList<String> pComandos() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("read");
        arrayList.add("write");
        arrayList.add("while");
        arrayList.add("if");
        arrayList.add("ident");
        arrayList.add("begin");
        arrayList.add("VAZIO");

        return arrayList;
    }

    public static ArrayList<String> pCmd() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("read");
        arrayList.add("write");
        arrayList.add("while");
        arrayList.add("if");
        arrayList.add("ident");
        arrayList.add("begin");
        return arrayList;
    }

    private static ArrayList<String> pCondicao() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("+");
        arrayList.add("-");
        arrayList.add("ident");
        arrayList.add("NumeroInteiro");
        arrayList.add("NumeroReal");
        arrayList.add("(");
        arrayList.add("VAZIO");
        return arrayList;
    }

    private static ArrayList<String> pRelacao() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("=");
        arrayList.add("<>");
        arrayList.add(">=");
        arrayList.add("<=");
        arrayList.add("<");
        arrayList.add(">");
        return arrayList;
    }

    public static ArrayList<String> pExpressao() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("+");
        arrayList.add("-");
        arrayList.add("ident");
        arrayList.add("NumeroInteiro");
        arrayList.add("NumeroReal");
        arrayList.add("(");
        arrayList.add("VAZIO");
        return arrayList;
    }

    private static ArrayList<String> pOpUn() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("+");
        arrayList.add("-");
        arrayList.add("VAZIO");
        return arrayList;
    }

    private static ArrayList<String> pOutrosTermos() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("+");
        arrayList.add("-");
        arrayList.add("VAZIO");
        return arrayList;
    }

    public static ArrayList<String> pOpAd() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("+");
        arrayList.add("-");
        return arrayList;
    }

    public static ArrayList<String> pTermo() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("+");
        arrayList.add("-");
        arrayList.add("ident");
        arrayList.add("NumeroInteiro");
        arrayList.add("NumeroReal");
        arrayList.add("(");
        arrayList.add("VAZIO");
        return arrayList;
    }

    private static ArrayList<String> pMaisFatores() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("*");
        arrayList.add("/");
        arrayList.add("VAZIO");
        return arrayList;
    }

    public static ArrayList<String> pOpMul() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("*");
        arrayList.add("/");
        return arrayList;
    }

    private static ArrayList<String> pFator() {
        ArrayList<String> arrayList = new ArrayList<>();

        arrayList.add("ident");
        arrayList.add("numeroInteiro");
        arrayList.add("numeroReal");
        arrayList.add("(");

        return arrayList;
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc=" Metodos para carregar os Seguidores a partir do primeiro"> 
    private static ArrayList<String> montarPriemiroDoSeguidor(String primeiro) {
        ArrayList<String> listaAux;
        switch (primeiro) {
            case PCORPO:
                listaAux = pCorpo();
                break;
            case PDC:
                listaAux = pDc();
                break;
            case PDCV:
                listaAux = pDcV();
                break;
            case PTIPOVAR:
                listaAux = pTipoVar();
                break;
            case PVARIAVEIS:
                listaAux = pVariaveis();
                break;
            case PMAISVAR:
                listaAux = pMaisVar();
                break;
            case PDCP:
                listaAux = pDcP();
                break;
            case PPARAMETROS:
                listaAux = pParametros();
                break;
            case PLISTAPAR:
                listaAux = pListaPar();
                break;
            case PMAISPAR:
                listaAux = pMaisPar();
                break;
            case PCORPOP:
                listaAux = pCorpoP();
                break;
            case PDCLOC:
                listaAux = pDcLoc();
                break;
            case PLISTAARG:
                listaAux = pListaArg();
                break;
            case PARGUMENTOS:
                listaAux = pArgumentos();
                break;
            case PMAISIDENT:
                listaAux = pMaisIdent();
                break;
            case PPFALSA:
                listaAux = pPFalsa();
                break;
            case PCOMANDOS:
                listaAux = pComandos();
                break;
            case PCMD:
                listaAux = pCmd();
                break;
            case PCONDICAO:
                listaAux = pCondicao();
                break;
            case PRELACAO:
                listaAux = pRelacao();
                break;
            case PEXPRESSAO:
                listaAux = pExpressao();
                break;
            case POPUN:
                listaAux = pOpUn();
                break;
            case POUTROSTERMOS:
                listaAux = pOutrosTermos();
                break;
            case POPAD:
                listaAux = pOpAd();
                break;
            case PTERMO:
                listaAux = pTermo();
                break;
            case PMAISFATORES:
                listaAux = pMaisFatores();
                break;
            case POPMUL:
                listaAux = pOpMul();
                break;
            case PFATOR:
                listaAux = pFator();
                break;
            default:
                listaAux = new ArrayList<>();
                break;
        }

        if (listaAux.contains("VAZIO")) {
            listaAux.removeAll(Arrays.asList("VAZIO"));
        }
        return listaAux;
    }
    //</editor-fold>

    /**
     * Método responsável por carregar os token sincronizadores
     * @return HashMap
    */
    public static HashMap carregaSincronizacao() {

        //HashMap<String, List<String>> hashSincrozinacao = new HashMap<>();
        HashMap<String, ArrayList<String>> hashSincrozinacao = new HashMap<>();
       
        
        //<programa>
        hashSincrozinacao.put("programa_program", new ArrayList(Arrays.asList("ident", ";" , "var", "procedure", "begin", ".", "end")));//adicionado end
        hashSincrozinacao.put("programa_ident", new ArrayList(Arrays.asList(";", ".", "var", "procedure", "begin", "end"))); //adicionado end
        hashSincrozinacao.put("programa_;", new ArrayList(Arrays.asList(".", "var", "procedure", "begin","end"))); //adicionado end
        hashSincrozinacao.put("programa_corpo", new ArrayList( Arrays.asList(".")));
        //<corpo>
        hashSincrozinacao.put("corpo_dc", new ArrayList(Arrays.asList("begin","read", "write","while","if","ident","begin","end")));
        hashSincrozinacao.put("corpo_begin", new ArrayList(Arrays.asList("read", "write","while","if","ident","begin","end")));
        hashSincrozinacao.put("corpo_comandos", new ArrayList(Arrays.asList("end")));
        //<dc>
        hashSincrozinacao.put("dc_dcV", new ArrayList(Arrays.asList("procedure")));
        //<dc_v>        
        hashSincrozinacao.put("dcV_var", new ArrayList(Arrays.asList("ident",":","real","integer", ";", "var")));
        hashSincrozinacao.put("dcV_variaveis", new ArrayList(Arrays.asList(":","real","integer",";","var")));
        hashSincrozinacao.put("dcV_:", new ArrayList(Arrays.asList("real","integer",";","var")));
        hashSincrozinacao.put("dcV_tipoVar", new ArrayList(Arrays.asList(";","var")));
        hashSincrozinacao.put("dcV_;", new ArrayList(Arrays.asList("var")));
        //Variaveis
        hashSincrozinacao.put("variaveis_ident", montarPriemiroDoSeguidor(PMAISVAR));
        //<Mais_var>
        hashSincrozinacao.put("maisVar_,", montarPriemiroDoSeguidor(PVARIAVEIS));
        //<dc_p>
        hashSincrozinacao.put("dcP_procedure", new ArrayList( Arrays.asList("ident", "(", ";", "var", "begin", "procedure"))); 
        hashSincrozinacao.put("dcP_ident",  new ArrayList(Arrays.asList("(",";", "var", "begin", "procedure")));
        hashSincrozinacao.put("dcP_parametros", new ArrayList(Arrays.asList(";", "var", "begin", "procedure"))); 
        hashSincrozinacao.put("dcP_;",  new ArrayList(Arrays.asList("var", "begin", "procedure")));
        hashSincrozinacao.put("dcP_corpoP", montarPriemiroDoSeguidor(PDCP));
        //<parametros>
        hashSincrozinacao.put("parametros_(",  new ArrayList(Arrays.asList("ident",")")));
        hashSincrozinacao.put("parametros_listaPar",  new ArrayList(Arrays.asList(")")));
        //<lista_par>
        hashSincrozinacao.put("listaPar_variaveis",  new ArrayList(Arrays.asList(":","real","integer",";")));
        hashSincrozinacao.put("listaPar_:",  new ArrayList(Arrays.asList("real","integer",";")));
        hashSincrozinacao.put("listaPar_tipoVar",  new ArrayList(Arrays.asList(";")));
        //<mais_par>
        hashSincrozinacao.put("maisPar_;", montarPriemiroDoSeguidor(PLISTAPAR));
        //<corpo_p>
        hashSincrozinacao.put("corpoP_dcLoc",  new ArrayList(Arrays.asList("begin","write","while","if","ident","end",";")));
        hashSincrozinacao.put("corpoP_begin",  new ArrayList(Arrays.asList("write","while","if","ident","end",";")));
        hashSincrozinacao.put("corpoP_comandos",  new ArrayList(Arrays.asList("end",";")));
        hashSincrozinacao.put("corpoP_end", new ArrayList(Arrays.asList(";")));
        //<Lista_arg>
        hashSincrozinacao.put("listaArg_(", new ArrayList(Arrays.asList("ident",")")));
        hashSincrozinacao.put("listaArg_argumentos", new ArrayList(Arrays.asList(")")));
        //<Argumentos>
        hashSincrozinacao.put("argumentos_ident", montarPriemiroDoSeguidor(PMAISIDENT));
        //<mais_ident>
        hashSincrozinacao.put("maisIdent_;", montarPriemiroDoSeguidor(PARGUMENTOS));
        //<pfalse>
        hashSincrozinacao.put("pFalsa_else", montarPriemiroDoSeguidor(PCMD));
        //<comandos>
        hashSincrozinacao.put("comandos_cmd", new ArrayList(Arrays.asList(";","read","write","while","if","ident","begin")));
        hashSincrozinacao.put("comandos_;", new ArrayList(Arrays.asList("read","write","while","if","ident","begin")));
        //<cmd>
        hashSincrozinacao.put("cmd_read", new ArrayList(Arrays.asList("(","ident",")")));
        hashSincrozinacao.put("cmd_read_(", new ArrayList(Arrays.asList("ident",")")));
        hashSincrozinacao.put("cmd_read_variaveis", new ArrayList(Arrays.asList(")")));
        
        hashSincrozinacao.put("cmd_write", new ArrayList(Arrays.asList("(","ident",")")));
        hashSincrozinacao.put("cmd_write_(", new ArrayList(Arrays.asList("ident",")")));
        hashSincrozinacao.put("cmd_write_variaveis", new ArrayList(Arrays.asList(")")));
        
        hashSincrozinacao.put("cmd_while", new ArrayList(Arrays.asList("+","-","ident","numeroInteiro","numeroReal","(","do","read","write","while","if","ident","begin")));
        hashSincrozinacao.put("cmd_while_condicao", new ArrayList(Arrays.asList("do","read","write","while","if","ident","begin")));
        hashSincrozinacao.put("cmd_while_do", new ArrayList(Arrays.asList("read","write","while","if","ident","begin")));
        
        hashSincrozinacao.put("cmd_if", new ArrayList(Arrays.asList("+","-","ident","numeroInteiro","numeroReal","(","then","read","write","while","if","ident","begin","else")));
        hashSincrozinacao.put("cmd_if_condicao",new ArrayList( Arrays.asList("then","read","write","while","if","ident","begin","else")));
        hashSincrozinacao.put("cmd_if_then",new ArrayList( Arrays.asList("read","write","while","if","ident","begin","else")));
        hashSincrozinacao.put("cmd_if_cmd", new ArrayList(Arrays.asList("else")));
        
        hashSincrozinacao.put("cmd_ident", new ArrayList(Arrays.asList(":=","+","-","ident","numeroInteiro","numeroReal","(")));
        hashSincrozinacao.put("cmd_ident_:=", new ArrayList(Arrays.asList("+","-","ident","numeroInteiro","numeroReal","(")));
        hashSincrozinacao.put("cmd_ident_expressao", new ArrayList(Arrays.asList("(")));
        hashSincrozinacao.put("cmd_ident_listaArg", montarPriemiroDoSeguidor(PLISTAARG));
                
        hashSincrozinacao.put("cmd_begin", new ArrayList(Arrays.asList("read", "write", "while", "if", "ident", "begin", "end")));
        hashSincrozinacao.put("cmd_begin_comandos", new ArrayList(Arrays.asList("end")));
        //<condicao>
        hashSincrozinacao.put("condicao_expressao", new ArrayList(Arrays.asList("+","-","ident","numeroInteiro","numeroReal","(")));
        hashSincrozinacao.put("condicao_relacao",new ArrayList( Arrays.asList("ident","numeroInteiro","numeroReal","(")));
        //<Expressao>
        hashSincrozinacao.put("expressao_termo", montarPriemiroDoSeguidor(POUTROSTERMOS));
        //<outros_termos>
        hashSincrozinacao.put("outrosTermos_opAd", new ArrayList(Arrays.asList("+","-","ident","numeroInteiro", "numeroReal","(")));
        hashSincrozinacao.put("outrosTermos_termo", new ArrayList(Arrays.asList("+","-")));
        //<termo>
        hashSincrozinacao.put("termo_opUn", new ArrayList(Arrays.asList("ident","numeroInteiro","numeroReal","(","*","/")));
        hashSincrozinacao.put("termo_fator", new ArrayList(Arrays.asList("*","/")));
        //<mais_faores>        
        hashSincrozinacao.put("maisFatores_opMul", new ArrayList(Arrays.asList("ident","numeroInteiro","numeroReal","(","*","/")));
        hashSincrozinacao.put("maisFatores_fator", new ArrayList(Arrays.asList("*","/")));
        //<fator>
        hashSincrozinacao.put("fator_(", new ArrayList(Arrays.asList("+","-","ident","numeroInteiro","numeroReal","(",")")));
        
        
        
        return hashSincrozinacao;
    }

    //<editor-fold defaultstate="collapsed" desc="Declaração de Variaveis Finais"> 
    private static final String PCORPO = "pCorpo";
    private static final String PDC = "pDc";
    private static final String PDCV = "pDcV";
    private static final String PTIPOVAR = "pTipoVar";
    private static final String PVARIAVEIS = "pVariaveis";
    private static final String PMAISVAR = "pMaisVar";
    private static final String PDCP = "pDcP";
    private static final String PPARAMETROS = "pParametros";
    private static final String PLISTAPAR = "pListaPar";
    private static final String PMAISPAR = "pMaisPar";
    private static final String PCORPOP = "pCorpoP";
    private static final String PDCLOC = "pDcLoc";
    private static final String PLISTAARG = "pListaArg";
    private static final String PARGUMENTOS = "pArgumentos";
    private static final String PMAISIDENT = "pMaisIdent";
    private static final String PPFALSA = "pPFalsa";
    private static final String PCOMANDOS = "pComandos";
    private static final String PCMD = "pCmd";
    private static final String PCONDICAO = "pCondicao";
    private static final String PRELACAO = "pRelacao";
    private static final String PEXPRESSAO = "pExpressao";
    private static final String POPUN = "pOpUn";
    private static final String POUTROSTERMOS = "pOutrosTermos";
    private static final String POPAD = "pOpAd";
    private static final String PTERMO = "pTermo";
    private static final String PMAISFATORES = "pMaisFatores";
    private static final String POPMUL = "pOpMul";
    private static final String PFATOR = "pFator";
    //</editor-fold>

}
